
package com.trydofor.id.exec;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.springframework.core.io.ByteArrayResource;

import com.trydofor.aloe.exception.Exceptions;
import com.trydofor.id.doer.shell.ArgChecker;
import com.trydofor.id.doer.shell.Command;
import com.trydofor.id.doer.shell.Executer;
import com.trydofor.id.doer.shell.Outcome;
import com.trydofor.id.ware.SpringFactory;
import com.trydofor.id.xnet.ConfBuilder;

/**
 * @author : Shi Rongjiu (www.trydofor.com)
 */
public class SpringExe implements Executer {
    
    private final Command       listBeans;
    private final Command       removeBean;
    private final Command       loadConfig;
    private final Command       getBean;
    
    private final SpringFactory factory;
    
    /**
     * constructor
     * 
     * @param factory the ware context
     * @throws NullPointerException if doer or factory is null
     */
    public SpringExe(SpringFactory factory) {
        Exceptions.checkNullPointer(factory);
        this.factory = factory;
        this.listBeans = SpringCmd.listBeans();
        this.removeBean = SpringCmd.removeBean();
        this.loadConfig = SpringCmd.loadConfig();
        this.getBean = SpringCmd.getBean();
    }
    
    /**
     * {@inheritDoc}
     */
    public Outcome execute(Command command, Map<String, String> argdata) {
        
        String err = ArgChecker.check(command, argdata);
        if (err != null) return new Outcome(-1, null, err);
        
        if (listBeans.getAlias().equals(command.getAlias())) {
            return listBeans(command, argdata);
        }
        else if (loadConfig.getAlias().equals(command.getAlias())) {
            return loadConfig(command, argdata);
        }
        else if (removeBean.getAlias().equals(command.getAlias())) {
            return removeBean(command, argdata);
        }
        else if (getBean.getAlias().equals(command.getAlias())) {
            return getBean(command, argdata);
        }
        return new Outcome(-1, null, "Command is unsupported:" + command);
    }
    
    // ------------------
    private Outcome listBeans(Command command, Map<String, String> argdata) {
        try {
            String pat = argdata.get("pattern");
            
            String err = null;
            Pattern p = null;
            if (pat != null) {
                try {
                    p = Pattern.compile(pat);
                }
                catch (Exception e) {
                    err = e.toString();
                    p = null;
                }
            }
            
            StringBuilder sb = new StringBuilder();
            int index = 1;
            for (String str : factory.getAllBeanNames()) {
                if (p != null && !p.matcher(str).find()) {
                    continue;
                }
                lineIt(sb, index, str);
                index++;
            }
            return new Outcome(0, sb.toString(), err);
        }
        catch (Exception e) {
            return new Outcome(-1, null, Exceptions.printStackTrace(e));
        }
    }
    
    private Outcome removeBean(Command command, Map<String, String> argdata) {
        try {
            String nm = argdata.get("name");
            boolean ok = factory.removeBean(nm);
            
            return new Outcome(0, "remove bean:" + nm + " ," + ok, null);
        }
        catch (Exception e) {
            return new Outcome(-1, null, Exceptions.printStackTrace(e));
        }
    }
    
    private Outcome getBean(Command command, Map<String, String> argdata) {
        try {
            String nm = argdata.get("name");
            String obj = String.valueOf(factory.getInstance(nm));
            return new Outcome(0, "get bean(" + nm + "):" + obj, null);
        }
        catch (Exception e) {
            return new Outcome(-1, null, Exceptions.printStackTrace(e));
        }
    }
    
    private Outcome loadConfig(Command command, Map<String, String> argdata) {
        String conf = argdata.get("file");
        try {
            InputStream ins = ConfBuilder.loadStream(conf);
            if (ins == null) {
                return new Outcome(-2, null, "config not found: " + conf);
            }
            String[] old = factory.getAllBeanNames();
            int cnt = factory.registerXmlConfBeans(new ByteArrayResource(ConfBuilder.streamToBytes(ins)));
            String[] neu = factory.getAllBeanNames();
            StringBuilder sb = new StringBuilder();
            sb.append(cnt);
            sb.append(" beans in the config:\n");
            sb.append(conf);
            
            if (cnt > 0) {
                sb.append("\n====\n");
                List<String> lsn = new ArrayList<String>();
                lsn.addAll(Arrays.asList(neu));
                lsn.removeAll(Arrays.asList(old));
                int index = 1;
                for (String str : lsn) {
                    lineIt(sb, index, str);
                    index++;
                }
            }
            
            return new Outcome(0, sb.toString(), null);
        }
        catch (Exception e) {
            return new Outcome(-1, null, Exceptions.printStackTrace(e));
        }
    }
    
    private void lineIt(StringBuilder sb, int i, String s) {
        if (i < 10) sb.append(" ");
        if (i < 100) sb.append(" ");
        sb.append(i);
        sb.append(". ");
        sb.append(s);
        sb.append("\n");
    }
}
